home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / filesyst / ncpfs / ipxripd-.000 / ipxripd- / ipxripd / ipxripd.c < prev    next >
C/C++ Source or Header  |  1996-02-03  |  17KB  |  837 lines

  1. /*
  2.     IPX routing daemon
  3.  
  4.     Copyright (C) 1994, 1995  Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>
  5.     Copyright (C) 1996, Volker Lendecke <lendecke@namu01.gwdg.de>
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21. */
  22. /* done: filter my broadcasts for proper aging */
  23. /* done: age each iface separately */
  24. /* done: DONTROUTE ioctl */
  25. /* done: shutdown */
  26. /* done: logovani ... */
  27. /* done: full daemonize */
  28.  
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <sys/types.h>
  32. #include <sys/time.h>
  33. #include <sys/ioctl.h>
  34. #include <unistd.h>
  35. #include <fcntl.h>
  36. #include <signal.h>
  37. #include <errno.h>
  38. #include <string.h>
  39. #include <sys/socket.h>
  40. #include <netinet/in.h>
  41. #include <linux/ipx.h>
  42. #include "ipxutil.h"
  43. #include "ipxkern.h"
  44. #include "ipxrip.h"
  45. #include "ipxd.h"
  46.  
  47. typedef unsigned char ifc_timer;
  48.  
  49. struct rip_table
  50. {
  51.      IPXNet network;
  52.     hop_t hops;
  53.     tick_t ticks;
  54.     IPXNode router_node;
  55.     struct ipx_interface *router_interface;
  56.  
  57.     ifc_timer timers[MAX_IFACE]; /* 0<timer<EXPIRE_TIME =>
  58.                     net is reachable via iface */
  59.                      /* timer>=EXPIPE_TIME => net is not r. */
  60.     struct rip_table* next;
  61. };
  62.  
  63. struct rip_table *rtable = NULL;
  64.  
  65. static IPXNet
  66. ifc_net(struct ipx_interface *ifc)
  67. {
  68.     return ntohl(ifc->r_output.dest_addr.sipx_network);
  69. }
  70.  
  71. static IPXNet
  72. rt_net(struct rip_table *rt)
  73. {
  74.     return ifc_net(rt->router_interface);
  75. }
  76.  
  77. /* get some ipx socket */
  78. static int
  79. ipx_socket(void)
  80. {
  81.     struct ipx_interface *ifc = first_interface();
  82.  
  83.     if (first_interface == NULL)
  84.     {
  85.         LOG_START;
  86.         fprintf(log_file, "No ipx socket available\n");
  87.         LOG_END;
  88.         exit(1);
  89.     }
  90.     return ifc->r_output.sk;
  91. }
  92.  
  93. static int
  94. is_expired(ifc_timer* tm)
  95. {
  96.     return *tm>=EXPIRE_TIME;
  97. }
  98.  
  99. /* Do I forward packets targeted to rt->network coming over interface
  100.  * ifc?
  101.  */
  102. static int
  103. is_rt_target(struct rip_table *rt, struct ipx_interface *ifc)
  104. {
  105.     return is_expired(rt->timers + ifc_get_index(ifc));
  106. }
  107.  
  108. /* set up the timers in rt so that only ifc is reachable.
  109.  */
  110. static void
  111. setup_timers(struct rip_table* rt, struct ipx_interface* ifc)
  112. {
  113.     ifc_timer* tm;
  114.     
  115.     for(tm=rt->timers; tm < rt->timers+MAX_IFACE; tm += 1)
  116.     {
  117.         *tm=EXPIRE_TIME;
  118.     }
  119.     rt->timers[ifc_get_index(ifc)]=0;
  120. }
  121.  
  122. static void
  123. output_flushall()
  124. {
  125.     struct ipx_interface *ifc = first_interface();
  126.  
  127.     while (ifc != NULL)
  128.     {
  129.         ipx_rip_output_flush(&(ifc->r_output));
  130.         ifc = next_interface(ifc);
  131.     }
  132. }
  133.  
  134. static void
  135. output_set_destination(struct ipx_interface *ifc,
  136.                IPXNode dest_node, IPXPort dest_port)
  137. {
  138.     if (ifc == NULL)
  139.     {
  140.         ifc = first_interface();
  141.  
  142.         while (ifc != NULL)
  143.         {
  144.             ipx_rip_output_set_destination(&(ifc->r_output),
  145.                                dest_node, dest_port);
  146.             ifc = next_interface(ifc);
  147.         }
  148.     }
  149.     else
  150.     {
  151.         ipx_rip_output_set_destination(&(ifc->r_output), dest_node,
  152.                            dest_port);
  153.     }
  154. }
  155.  
  156. /* Broadcast the existence of the route rt to all interfaces through
  157.  * which rt's target is not directly reachable.
  158.  */
  159. static void
  160. output_broadcast(struct rip_table *rt, int down_allow)
  161. {
  162.     struct ipx_interface *ifc = first_interface();
  163.  
  164.     while (ifc != NULL)
  165.     {
  166.         if (is_expired(&(rt->timers[ifc_get_index(ifc)])))
  167.         {
  168.             ipx_rip_output_response(&(ifc->r_output),rt->network,
  169.                         rt->hops,rt->ticks,down_allow);
  170.         }
  171.         ifc = next_interface(ifc);
  172.     }
  173. }
  174.  
  175. static int
  176. output_sendto(int sock, void *buffer, int size, struct sockaddr_ipx *daddr)
  177. {
  178.     int res;
  179.     
  180.     DL_ENTRY;
  181.     DL_START;
  182.     fprintf(log_file,"Sending RIP to ");
  183.     ipx_fprint_saddr(log_file,daddr);
  184.     fprintf(log_file,"\n");
  185.     ipx_rip_fdump(log_file,buffer,size);
  186.     DL_END;
  187.  
  188.     res=sendto(sock,(void*)buffer,size,0,
  189.            (struct sockaddr*)daddr,sizeof(*daddr));
  190.     if (res==-1)
  191.     {
  192.         LOG_START;
  193.         fprintf(log_file,"sendto: %s\n",strerror(errno));
  194.         LOG_END;
  195.     }
  196.     return res;
  197. }
  198.  
  199. static void
  200. fprint_route(FILE *file, struct rip_table *rt)
  201. {
  202.     int i;
  203.     
  204.     LOG_START;
  205.     fprintf(file,"dst:");
  206.     ipx_fprint_network(file,rt->network);
  207.     fprintf(file," h:%d t:%d rtr:",rt->hops,rt->ticks);
  208.     ipx_fprint_network(file,rt_net(rt));
  209.     fprintf(file,":");
  210.     ipx_fprint_node(file,rt->router_node);
  211.     fprintf(file," ");
  212.  
  213.     for (i = first_ifc_index(); i >= 0; i = next_ifc_index(i))
  214.     {
  215.         ifc_timer* tm = &(rt->timers[i]);;
  216.         fprintf(file,"%i",is_expired(tm)?0:1);
  217.         DL_START;
  218.         fprintf(file,"(%i)",(int)*tm);
  219.         DL_END;
  220.     }
  221.     LOG_END;
  222. }
  223.  
  224. void
  225. fdump_routes(FILE *file)
  226. {
  227.     struct rip_table *rt;
  228.     
  229.     LOG_START;
  230.     fprintf(file,"IPX routing database:\n");
  231.     for(rt=rtable; rt!=NULL; rt=rt->next)
  232.     {
  233.         fprint_route(file,rt);
  234.         fprintf(file,"\n");
  235.     }
  236.     LOG_END;
  237. }
  238.  
  239.  
  240. static struct rip_table*
  241. add_route(IPXNet to, hop_t h, tick_t t, struct ipx_interface *ifc,
  242.       IPXNode rt_node)
  243. {
  244.     struct rip_table *rt;
  245.  
  246.     rt=(struct rip_table*)malloc(sizeof(struct rip_table));
  247.  
  248.     if (rt == NULL)
  249.     {
  250.         LOG_START;
  251.         fprintf(log_file,"ipxripd: out of memory in add_route\n");
  252.         LOG_END;
  253.         return NULL;
  254.     }
  255.  
  256.     rt->network=to;
  257.     rt->hops=h;
  258.     rt->ticks=t;
  259.     rt->router_interface=ifc;
  260.     ipx_assign_node(rt->router_node,rt_node);
  261.     setup_timers(rt,ifc);
  262.     rt->next=rtable;
  263.     rtable=rt;
  264.     return rt;
  265. }
  266.  
  267. static void
  268. delete_route(struct rip_table* d)
  269. {
  270.     struct rip_table **r;
  271.     for(r=&rtable; *r!=NULL; r=&((*r)->next))
  272.     {
  273.         if (*r==d)
  274.         {
  275.             *r=d->next;
  276.             free(d);
  277.             return;
  278.         }
  279.     }
  280. }
  281.  
  282. static void
  283. delete_invalid_routes(void)
  284. {
  285.     struct rip_table **r = &rtable;
  286.  
  287.     while (*r != NULL)
  288.     {
  289.         if ((*r)->hops >= IPX_RIP_NET_DOWN)
  290.         {
  291.             struct rip_table *d = *r;
  292.             *r = (*r)->next;
  293.             free(d);
  294.         }
  295.         else
  296.         {
  297.             r = &((*r)->next);
  298.         }
  299.     }
  300. }
  301.  
  302. static void
  303. ipx_rip_rt_add(struct rip_table *rt)
  304. {
  305.     if(ipx_kern_route_add(ipx_socket(), rt->network, rt_net(rt),
  306.                   rt->router_node) < 0)
  307.     {
  308.         LOG_START;
  309.         fprintf(log_file,"Cannot add route to network ");
  310.         ipx_fprint_network(log_file,rt->network);
  311.         fprintf(log_file,"\n%s\n",ipx_err_string);
  312.         LOG_END;
  313.     }
  314. }
  315.  
  316. static void
  317. ipx_rip_rt_del(IPXNet net)
  318. {
  319.     if (ipx_kern_route_delete(ipx_socket(), net)<0)
  320.     {
  321.         LOG_START;
  322.         fprintf(log_file,"Cannot delete route to network ");
  323.         ipx_fprint_network(log_file,net);
  324.         fprintf(log_file,"\n%s\n",ipx_err_string);
  325.         LOG_END;
  326.     }
  327. }
  328.  
  329. static void
  330. handle_rip_request(struct rip_entry *re, struct ipx_interface *src_ifc)
  331. {
  332.     struct rip_table *cur;
  333.  
  334.     if (re->network==htonl(IPX_RIP_GENERAL_RQ))
  335.     {
  336.         for(cur=rtable; cur!=NULL; cur=cur->next)
  337.         {
  338.             if (is_rt_target(cur, src_ifc))
  339.             {
  340.                 ipx_rip_output_response(&(src_ifc->r_output),
  341.                             cur->network,
  342.                             cur->hops,
  343.                             cur->ticks,0);
  344.             }
  345.         }
  346.     }
  347.     else
  348.     {
  349.         for(cur=rtable; cur!=NULL; cur=cur->next)
  350.         {
  351.             if (   (htonl(re->network)==cur->network)
  352.                 && (   (is_rt_target(cur, src_ifc))
  353.                 || (ifc_net(src_ifc)==htonl(re->network))))
  354.             {
  355.                 ipx_rip_output_response(&(src_ifc->r_output),
  356.                             cur->network,
  357.                             cur->hops,
  358.                             cur->ticks,0);
  359.             }
  360.         }
  361.     }
  362. }
  363.  
  364. static void
  365. handle_rip_response(struct rip_entry *re, struct ipx_interface *src_ifc,
  366.             IPXNode src_node)
  367. {
  368.     struct rip_table *cur;
  369.  
  370.     re->hops=ntohs(re->hops)+1;
  371.     re->ticks=ntohs(re->ticks)+src_ifc->ticks;
  372.  
  373.     for(cur=rtable; cur!=NULL; cur=cur->next)
  374.     {
  375.         if (cur->network != htonl(re->network))
  376.         {
  377.             continue;
  378.         }
  379.         if (cur->network==rt_net(cur))
  380.         {
  381.             /* don't change routes to ifaces */
  382.             return;
  383.         }
  384.         if (re->hops <= IPX_RIP_NET_DOWN)
  385.         {
  386.             if (!(   (re->ticks < cur->ticks)
  387.                   || (   (re->ticks == cur->ticks)
  388.                   && (re->hops  <= cur->hops))))
  389.             {
  390.                 /* route re-> is worse */
  391.                 return;
  392.             }
  393.  
  394.             /* route is at least good as
  395.              * existing one */
  396.  
  397.             if (   (re->ticks==cur->ticks)
  398.                 && (re->hops==cur->hops))
  399.             {
  400.                 /* new route has the same cost - reset timer*/
  401.                 if (!(  (ifc_net(src_ifc)==rt_net(cur))
  402.                       && (!ipx_node_equal(cur->router_node,
  403.                               src_node))))
  404.                 {
  405.                     cur->timers[ifc_get_index(src_ifc)]=0;
  406.                 }
  407.             }
  408.             else
  409.             {
  410.                 /* new route is better */
  411.                 LOG_START;
  412.                 fprintf(log_file,"CHANGE ");
  413.                 fprint_route(log_file,cur);
  414.                 LOG_END;
  415.                         
  416.                 /* update table */
  417.                 cur->ticks=re->ticks;
  418.                 cur->hops=re->hops;
  419.                 cur->router_interface = src_ifc;
  420.                 ipx_assign_node(cur->router_node,
  421.                         src_node);
  422.                 setup_timers(cur,src_ifc);
  423.  
  424.                 LOG_START;
  425.                 fprintf(log_file,"\nto     ");
  426.                 fprint_route(log_file,cur);
  427.                 fprintf(log_file,"\n");
  428.                 LOG_END;
  429.     
  430.                 /* update kernel table */
  431.                 ipx_rip_rt_add(cur);
  432.                 /* send info bcast */
  433.                 output_broadcast(cur,0);
  434.             }
  435.         }
  436.         else
  437.         {
  438.             /* network down response */
  439.             if (ifc_net(src_ifc)==rt_net(cur))
  440.             {
  441.                 if (ipx_node_equal(cur->router_node, src_node))
  442.                 {
  443.                     LOG_START;
  444.                     fprintf(log_file,"DELETE ");
  445.                     fprint_route(log_file,cur);
  446.                     fprintf(log_file, " (net down)\n");
  447.                     LOG_END;
  448.                     /* update kernel table */
  449.                     ipx_rip_rt_del(cur->network);
  450.                     /* send info bcast */
  451.                     cur->hops=IPX_RIP_NET_DOWN;
  452.                     output_broadcast(cur,1);
  453.                     /* update table */
  454.                     delete_route(cur);
  455.                 }
  456.                 else
  457.                 { /* my router alive */
  458.                 }
  459.             }
  460.             else
  461.             {
  462.                 cur->timers[ifc_get_index(src_ifc)]
  463.                     =EXPIRE_TIME;
  464.             }
  465.         }
  466.         return;
  467.     }
  468.     if (re->hops<=IPX_RIP_NET_DOWN)
  469.     {
  470.         struct rip_table *rt=add_route(htonl(re->network),
  471.                            re->hops,re->ticks,
  472.                            src_ifc,src_node);
  473.         if (rt!=NULL)
  474.         {
  475.             /* update kernel table */
  476.             ipx_rip_rt_add(rt);
  477.             /* send info bcast */
  478.             output_broadcast(rt,0);
  479.             LOG_START;
  480.             fprintf(log_file,"ADD ");    
  481.             fprint_route(log_file,rt);
  482.             fprintf(log_file,"\n");
  483.             LOG_END;
  484.         }
  485.     }
  486. }
  487.  
  488. void
  489. handle_rip(struct rip_packet *pkt, int len, struct sockaddr_ipx* sipx,
  490.        struct ipx_interface *src_ifc)
  491. {
  492.     struct rip_entry *re=pkt->rip_entries;
  493.     int nent=(len-2)/8;
  494.  
  495.     if (ifc_net(src_ifc) != ntohl(sipx->sipx_network))
  496.     {
  497.         LOG_START;
  498.         fprintf(log_file,"RIP from non-local net on ifc ");
  499.         ipx_fprint_network(log_file, ifc_net(src_ifc));
  500.         fprintf(log_file, "\n");
  501.                 ipx_fprint_network(log_file,ntohl(sipx->sipx_network));
  502.         fprintf(log_file," (ignored)\n");
  503.         LOG_END;
  504.         return;
  505.     }
  506.     if (len<ipx_rip_size(1))
  507.     {
  508.         LOG_START;
  509.         fprintf(log_file,
  510.             "RIP packet too small len=%i (ignored)\n",len);
  511.         LOG_END;
  512.         return;
  513.     }
  514.     if (ipx_rip_size(nent)!=len)
  515.     {
  516.         LOG_START;
  517.         fprintf(log_file,"RIP packet bad size (ignored)\n");
  518.         LOG_END;
  519.         return;
  520.     }
  521.     if (   (ipx_node_equal(src_ifc->ifnode,sipx->sipx_node))
  522.         && ((unsigned short)sipx->sipx_port==htons(IPX_RIP_PORT)))
  523.     {
  524.         DL_START;
  525.         fprintf(log_file,"My packet (ignored)\n");
  526.         DL_END;
  527.         return;
  528.     }
  529.     switch (ntohs(pkt->operation))
  530.     {
  531.     case IPX_RIP_OP_REQUEST:
  532.         output_set_destination(src_ifc, sipx->sipx_node,
  533.                        ntohs(sipx->sipx_port));
  534.         for(;nent--;re++)
  535.         {
  536.             handle_rip_request(re, src_ifc);
  537.         }
  538.         ipx_rip_output_flush(&(src_ifc->r_output));
  539.         output_set_destination(src_ifc, IPX_BROADCAST, IPX_RIP_PORT);
  540.         break;
  541.     case IPX_RIP_OP_RESPONSE:
  542.         /* option: ignore responses from non RIP ports
  543.          * if (sipx->sipx_port!=htons(IPX_RIP_PORT)) return;
  544.          */
  545.         output_set_destination(NULL, IPX_BROADCAST, IPX_RIP_PORT);
  546.         for(;nent--;re++)
  547.         {
  548.             handle_rip_response(re, src_ifc, sipx->sipx_node);
  549.         }
  550.         output_flushall();
  551.         break;
  552.     default:
  553.         LOG_START;
  554.         fprintf(log_file,"Unknown RIP operation\n");
  555.         LOG_END;
  556.         break;
  557.     } 
  558. }
  559.  
  560. void
  561. ipx_rip_do_aging(int rate, int do_broadcast)
  562. {
  563.     struct rip_table *cur;
  564.     int routes_died = 0;
  565.     
  566.     DL_START;
  567.     fprintf(log_file,"DO RIP AGING\n");
  568.     DL_END;
  569.  
  570.     output_set_destination(NULL, IPX_BROADCAST, IPX_RIP_PORT);
  571.  
  572.     for(cur=rtable; cur!=NULL; cur=cur->next)
  573.     {
  574.         int i;
  575.         ifc_timer* tm;
  576.         for (i = first_ifc_index(); i >= 0; i = next_ifc_index(i))
  577.         {
  578.             tm = &(cur->timers[i]);
  579.             if (!is_expired(tm))
  580.             {
  581.                 (*tm)+=rate;
  582.             }
  583.         }
  584.         tm=cur->timers+ifc_get_index(cur->router_interface);
  585.  
  586.         /* cannot timeout iface !*/
  587.         if (cur->network==rt_net(cur))
  588.         {
  589.             *tm=0;
  590.         }
  591.  
  592.         if (is_expired(tm))
  593.         {
  594.             /* net is down */
  595.             LOG_START;
  596.             fprintf(log_file,"DELETE ");
  597.             fprint_route(log_file,cur);
  598.             fprintf(log_file," (timed out)\n");
  599.             LOG_END;
  600.             /* update kernel table */
  601.             ipx_rip_rt_del(cur->network);
  602.             /* send info bcast */
  603.             cur->hops=IPX_RIP_NET_DOWN;
  604.             output_broadcast(cur,1);
  605.             /* table to be updated, delayed */
  606.             routes_died = 1;
  607.         }
  608.         else
  609.         {
  610.             if (do_broadcast)
  611.             {
  612.                 output_broadcast(cur,0);
  613.             }
  614.         }
  615.     }
  616.     output_flushall();
  617.  
  618.     /* Delete all bogus routes */
  619.     if (routes_died != 0)
  620.     {
  621.         delete_invalid_routes();
  622.     }
  623. }
  624.  
  625. int
  626. ipx_rip_init_ifc(struct ipx_interface *ifc, IPXNet network,
  627.          char *device, int type, void *data)
  628. {
  629.     struct sockaddr_ipx sipx;
  630.  
  631.     if (ipx_rip_output_init(&(ifc->r_output), network) != 0)
  632.     {
  633.         LOG_START;
  634.         fprintf(log_file,
  635.             "out of memory allocating output buffer\n");
  636.         LOG_END;
  637.         return -1;
  638.     }
  639.     if (add_route(network,1,find_ticks(device),ifc,ifc->ifnode) == NULL)
  640.     {
  641.         LOG_START;
  642.         fprintf(log_file,
  643.             "cannot add route to iface (out of memory)\n");
  644.         LOG_END;
  645.         return -1;
  646.     }
  647.  
  648.     if ((ifc->r_output.sk = socket(AF_IPX, SOCK_DGRAM, PF_IPX)) < 0)
  649.     {
  650.         LOG_START;
  651.         fprintf(log_file,
  652.             "can't open socket: %s\n", strerror(errno));
  653.         LOG_END;
  654.         return -1;
  655.     }
  656.  
  657.     memset(&sipx, 0, sizeof(sipx));
  658.     sipx.sipx_family = AF_IPX;
  659.     sipx.sipx_network = htonl(network);
  660.     ipx_assign_node(sipx.sipx_node, IPX_THIS_NODE);
  661.     sipx.sipx_port = htons(IPX_RIP_PORT);
  662.     sipx.sipx_type = IPX_RIP_PTYPE;
  663.  
  664.     if (bind(ifc->r_output.sk, (struct sockaddr *)&sipx, sizeof(sipx)) < 0)
  665.     {
  666.         LOG_START;
  667.         fprintf(log_file, "can't bind socket: %s\n",
  668.             strerror(errno));
  669.         LOG_END;
  670.         return -1;
  671.     }
  672.  
  673.     if (ipx_kern_enable_broadcast(ifc->r_output.sk) != 0)
  674.     {
  675.         LOG_START;
  676.         fprintf(log_file, "cant' enable broadcast\n");
  677.         LOG_END;
  678.         return -1;
  679.     }
  680.     
  681.     LOG_START;
  682.     ipx_fprint_network(log_file, network);
  683.     fprintf(log_file,":");
  684.     ipx_fprint_node(log_file, ifc->ifnode);
  685.     fprintf(log_file,"\n");
  686.     LOG_END;
  687.     return 0;
  688. }
  689.  
  690. static void
  691. ipx_rip_deinit_ifc(struct ipx_interface *ifc)
  692. {
  693.     close(ifc->r_output.sk);
  694. }
  695.     
  696. static int
  697. ipx_rip_del_old_rt(IPXNet net, IPXNet rt_net, IPXNode node,
  698.            int type, void *data)
  699. {
  700.     if ((type & IPX_KRT_ROUTE) != 0)
  701.     {
  702.         /* remove old routes */
  703.         ipx_rip_rt_del(net);
  704.     }
  705.     return 0;
  706. }
  707.  
  708. void
  709. ipx_rip_del_old_routes(void)
  710. {
  711.     ipx_kern_scan_rtable(ipx_rip_del_old_rt, NULL);
  712. }
  713.  
  714. void
  715. ipx_rip_initial_broadcasts(void)
  716. {
  717.     struct rip_table* rt;
  718.     struct ipx_interface* ifc;
  719.  
  720.     ipx_rip_output_func=output_sendto;
  721.  
  722.     output_set_destination(NULL, IPX_BROADCAST, IPX_RIP_PORT);
  723.     for(rt=rtable;rt!=NULL;rt=rt->next)
  724.     {
  725.         output_broadcast(rt,0);
  726.     }
  727.     output_flushall();
  728.  
  729.     ifc = first_interface();
  730.     while (ifc != NULL)
  731.     {
  732.         ipx_rip_output_request(&(ifc->r_output),
  733.                        IPX_RIP_GENERAL_RQ);
  734.         ifc = next_interface(ifc);
  735.     }
  736.     output_flushall();
  737. }
  738.  
  739. void
  740. ipx_rip_initial_broadcast(struct ipx_interface *ifc)
  741. {
  742.     struct rip_table *cur;
  743.  
  744.     output_set_destination(ifc, IPX_BROADCAST, IPX_RIP_PORT);
  745.  
  746.     for(cur=rtable; cur!=NULL; cur=cur->next)
  747.     {
  748.         if (is_rt_target(cur, ifc))
  749.         {
  750.             ipx_rip_output_response(&(ifc->r_output),
  751.                         cur->network,
  752.                         cur->hops,
  753.                         cur->ticks,0);
  754.         }
  755.         if (cur->router_interface == ifc)
  756.         {
  757.             output_broadcast(cur, 0);
  758.         }
  759.     }
  760.     ipx_rip_output_request(&(ifc->r_output), IPX_RIP_GENERAL_RQ);
  761.     output_flushall();
  762. }
  763.     
  764. void
  765. ipx_rip_down_ifc(struct ipx_interface *ifc)
  766. {
  767.     struct rip_table *rt;
  768.     LOG_ENTRY;
  769.     LOG_START;
  770.     fprintf(log_file, "RIP DOWN INTERFACE ");
  771.     ipx_fprint_network(log_file, ifc_net(ifc));
  772.     fprintf(log_file, "\n");
  773.     LOG_END;
  774.  
  775.     for (rt = rtable; rt != NULL; rt = rt->next)
  776.     {
  777.         if (rt->router_interface != ifc)
  778.         {
  779.             /* rt is not via ifc */
  780.             continue;
  781.         }
  782.         
  783.         /* cur is via ifc, so down it */
  784.         LOG_START;
  785.         fprintf(log_file,"DELETE ");
  786.         fprint_route(log_file,rt);
  787.         fprintf(log_file, " (ifc down)\n");
  788.         LOG_END;
  789.         /* Update of kernel table unneccessary */
  790.  
  791.         /* send info bcast */
  792.         rt->hops=IPX_RIP_NET_DOWN;
  793.         output_broadcast(rt,1);
  794.     }
  795.     output_flushall();
  796.     delete_invalid_routes();
  797.     ipx_rip_deinit_ifc(ifc);
  798. }
  799.         
  800. void
  801. ipx_rip_done(void)
  802. {
  803.     struct rip_table* cur;
  804.     
  805.     LOG_ENTRY;
  806.     LOG_START;
  807.     fprintf(log_file,"RIP Shutdown start\n");
  808.     LOG_END;
  809.     
  810.     output_set_destination(NULL, IPX_BROADCAST, IPX_RIP_PORT);
  811.     for(cur=rtable; cur!=NULL; cur=cur->next)
  812.     {
  813.         /* update kernel table (don't delete ifaces)*/
  814.         if (cur->network != rt_net(cur))
  815.         {
  816.             ipx_rip_rt_del(cur->network);
  817.             LOG_START
  818.             fprintf(log_file,"DELETE ");
  819.             fprint_route(log_file,cur);
  820.             fprintf(log_file," (shutdown)\n");
  821.             LOG_END
  822.         }
  823.         /* send info bcast */
  824.         cur->hops=IPX_RIP_NET_DOWN;
  825.         output_broadcast(cur,1);
  826.         /* update table */
  827.         delete_route(cur);
  828.     }
  829.     output_flushall();
  830.  
  831.     LOG_ENTRY;
  832.     LOG_START;
  833.     fprintf(log_file,"RIP Shutdown end\n");
  834.     LOG_END;
  835. }
  836.  
  837.